﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media.Imaging;
using System.Windows;
using System.Windows.Media.Media3D;
using System.Windows.Controls;
using System.Windows.Input;
using Eniux.Windows.ThreeDEngine.Helper;
using System.Windows.Media;
using Eniux.Windows.ThreeDEngine.ExtensionMethods;
using System.Windows.Media.Animation;
using Eniux.Windows.ThreeDEngine.AttachObject;
using System.Globalization;
using System.Windows.Shapes;

namespace Eniux.Windows.ThreeDEngine.Visual3Ds
{
    /// <summary>
    /// ViewCube
    /// </summary>
    public class ViewCubeVisual3D : ModelVisual3D
    {

        #region 私有变量
        /// <summary>
        /// 中心点
        /// </summary>
        private readonly Dictionary<object, Vector3D> centerDictionary = new Dictionary<object, Vector3D>();
        /// <summary>
        /// 法线
        /// </summary>
        private readonly Dictionary<object, Vector3D> normalDictionary = new Dictionary<object, Vector3D>();

        /// <summary>
        /// 上行
        /// </summary>
        private readonly Dictionary<object, Vector3D> upDictionary = new Dictionary<object, Vector3D>();


        private int CubeR;// = 4;
        private int c1;// = 4;
        private int c2;// = 2 * CubeR;

        private Brush Background = Brushes.Silver;
        private Brush BackgroundMouseOver = Brushes.Orange;
        private Brush RelativeBackgroundMouseOver = Brushes.Gray;
        private Brush BorderBrush = Brushes.Black;
        private Brush BorderBrushMoverOver = Brushes.Yellow;
        private List<List<Layout>> LayoutCollection = new List<List<Layout>>();
        private List<Layout> LayoutItem ;
        //private Dictionary<Key, List<Layout>> dic = new Dictionary<Key, List<Layout>>();
        Material material;
        Material backmaterial;
        #endregion

        #region 注册依赖属性

        #region Center（中心点）
        /// <summary>
        /// 获取或设置中心点
        /// </summary>
        public Point3D Center
        {
            get { return (Point3D)GetValue(CenterProperty); }
            set { SetValue(CenterProperty, value); }
        }
        /// <summary>
        /// 中心点
        /// </summary>
        public static readonly DependencyProperty CenterProperty = DependencyProperty.Register(
            "Center", typeof(Point3D), typeof(ViewCubeVisual3D), new UIPropertyMetadata(new Point3D(0, 0, 0))); 
        #endregion
                   
        #region ModelUpDirection（模型向上方向）
        /// <summary>
        /// 获取或设置模型向上方向
        /// </summary>
        public Vector3D ModelUpDirection
        {
            get { return (Vector3D)GetValue(ModelUpDirectionProperty); }
            set { SetValue(ModelUpDirectionProperty, value); }
        }
        /// <summary>
        /// 模型向上方向
        /// </summary>
        public static readonly DependencyProperty ModelUpDirectionProperty =
            DependencyProperty.Register(
                "ModelUpDirection",
                typeof(Vector3D),
                typeof(ViewCubeVisual3D),
                new UIPropertyMetadata(new Vector3D(0, 0, 1), VisualModelChanged)); 
        #endregion
   
        #region Size(大小)
        /// <summary>
        /// 获取或设置大小
        /// </summary>
        public double Size
        {
            get { return (double)GetValue(SizeProperty); }
            set { SetValue(SizeProperty, value); }
        }

        /// <summary>
        /// 大小属性
        /// </summary>
        public static readonly DependencyProperty SizeProperty = DependencyProperty.Register(
            "Size", typeof(double), typeof(ViewCubeVisual3D), new UIPropertyMetadata(5.0)); 
        #endregion

        #region Viewport(3D视窗)
        /// <summary>
        /// 获取或设置3D视窗
        /// </summary>
        public Viewport3D Viewport
        {
            get { return (Viewport3D)GetValue(ViewportProperty); }
            set { SetValue(ViewportProperty, value); }
        }

        /// <summary>
        /// 3D视窗属性
        /// </summary>
        public static readonly DependencyProperty ViewportProperty = DependencyProperty.Register(
            "Viewport", typeof(Viewport3D), typeof(ViewCubeVisual3D), new PropertyMetadata(null, ViewportChanged));

        private static void ViewportChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((ViewCubeVisual3D)d).OnViewportChanged();
        }
        private void OnViewportChanged()
        {
        }
        #endregion

        #endregion

        #region 构造、析构

        /// <summary>
        /// 静态构造函数
        /// </summary>
        static ViewCubeVisual3D()
        {
            AttachViewCube.AddOwner(typeof(ViewCubeVisual3D));
        }
        /// <summary>
        /// 默认公共无参构造函数
        /// </summary>
        public ViewCubeVisual3D()
        {
            CubeR =c1=4;
            c2 = CubeR * 2;
            UpdateVisuals();
        }

        #endregion

        #region 方法

        /// <summary>
        /// 属性改变时调用该方法
        /// </summary>
        /// <param name="d"></param>
        /// <param name="e"></param>
        private static void VisualModelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((ViewCubeVisual3D)d).UpdateVisuals();
        }

        //protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
        //{
        //    base.OnPropertyChanged(e);
        //    UpdateVisuals();
        //}

        /// <summary>
        /// 透明度动画
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="toOpacity"></param>
        /// <param name="animationTime"></param>
        private void AnimateOpacity(Animatable obj, double toOpacity, double animationTime)
        {
            var a = new DoubleAnimation(toOpacity, new Duration(TimeSpan.FromMilliseconds(animationTime)))
            {
                AccelerationRatio = 0.3,
                DecelerationRatio = 0.5
            };
            obj.BeginAnimation(UIElement.OpacityProperty, a);
        }

        /// <summary>
        /// 更新Visuals
        /// </summary>
        private void UpdateVisuals()
        {
            Children.Clear();
            var up = ModelUpDirection;
            var right = new Vector3D(0, 1, 0);
            if (up.Z != 1)
            {
                right = new Vector3D(0, 0, 1);
            }

            var front = Vector3D.CrossProduct(right, up);

            #region 六个中心面

            addFace(front, up, Background, AttachViewCube.GetFrontText(this), Face.Front, Alignment.Center,new Thickness(0));
            addFace(-front, up, Background, AttachViewCube.GetBackText(this), Face.Back, Alignment.Center, new Thickness(0));
            addFace(right, up, Background, AttachViewCube.GetRightText(this), Face.Right, Alignment.Center, new Thickness(0));
            addFace(-right, up, Background, AttachViewCube.GetLeftText(this), Face.Left, Alignment.Center, new Thickness(0));
            addFace(up, right, Background, AttachViewCube.GetTopText(this), Face.Top, Alignment.Center, new Thickness(0));
            addFace(-up, -right, Background, AttachViewCube.GetBottomText(this), Face.Bottom, Alignment.Center, new Thickness(0)); 

            #endregion

            #region 八个角
            Center = new Point3D(CubeR, -CubeR, CubeR);
            addFace(front, up, Background, AttachViewCube.GetFrontText(this), Face.Front, Alignment.TopLeft, new Thickness(1,1,0,0));
            addFace(-right, up, Background, AttachViewCube.GetLeftText(this), Face.Left, Alignment.TopRight, new Thickness(0,1,1,0));
            addFace(up, right, Background, AttachViewCube.GetTopText(this), Face.Top, Alignment.BottomRight, new Thickness(0,0,1,1));
            LayoutItem=new List<Layout>();
            LayoutItem.Add(new Layout() { Face = Face.Front, Align = Alignment.TopLeft});
            LayoutItem.Add(new Layout() { Face = Face.Left, Align = Alignment.TopRight });
            LayoutItem.Add(new Layout() { Face = Face.Top, Align = Alignment.BottomRight });
            LayoutCollection.Add(LayoutItem);

            Center = new Point3D(CubeR, CubeR, CubeR);
            addFace(front, up, Background, AttachViewCube.GetFrontText(this), Face.Front, Alignment.TopRight, new Thickness(0,1,1,0));
            addFace(right, up, Background, AttachViewCube.GetRightText(this), Face.Right, Alignment.TopLeft, new Thickness(1,1,0,0));
            addFace(up, right, Background, AttachViewCube.GetTopText(this), Face.Top, Alignment.TopRight, new Thickness(0,1,1,0));
            LayoutItem = new List<Layout>();
            LayoutItem.Add(new Layout() { Face = Face.Front, Align = Alignment.TopRight });
            LayoutItem.Add(new Layout() { Face = Face.Right, Align = Alignment.TopLeft });
            LayoutItem.Add(new Layout() { Face = Face.Top, Align = Alignment.TopRight });
            LayoutCollection.Add(LayoutItem);

            Center = new Point3D(CubeR, -CubeR, -CubeR);
            addFace(front, up, Background, AttachViewCube.GetFrontText(this), Face.Front, Alignment.BottomLeft, new Thickness(1,0,0,1));
            addFace(-right, up, Background, AttachViewCube.GetLeftText(this), Face.Left, Alignment.BottomRight, new Thickness(0,0,1,1));
            addFace(-up, -right, Background, AttachViewCube.GetBottomText(this), Face.Bottom, Alignment.TopRight, new Thickness(0,1,1,0));
            LayoutItem = new List<Layout>();
            LayoutItem.Add(new Layout() { Face = Face.Front, Align = Alignment.BottomLeft });
            LayoutItem.Add(new Layout() { Face = Face.Left, Align = Alignment.BottomRight });
            LayoutItem.Add(new Layout() { Face = Face.Bottom, Align = Alignment.TopRight });
            LayoutCollection.Add(LayoutItem);


            Center = new Point3D(CubeR, CubeR, -CubeR);
            addFace(front, up, Background, AttachViewCube.GetFrontText(this), Face.Front, Alignment.BottomRight, new Thickness(0, 0, 1, 1));
            addFace(right, up, Background, AttachViewCube.GetRightText(this), Face.Right, Alignment.BottomLeft, new Thickness(1, 0, 0, 1));
            addFace(-up, -right, Background, AttachViewCube.GetBottomText(this), Face.Bottom, Alignment.BottomRight, new Thickness(0, 0, 1, 1));
            LayoutItem = new List<Layout>();
            LayoutItem.Add(new Layout() { Face = Face.Front, Align = Alignment.BottomRight });
            LayoutItem.Add(new Layout() { Face = Face.Right, Align = Alignment.BottomLeft });
            LayoutItem.Add(new Layout() { Face = Face.Bottom, Align = Alignment.BottomRight });
            LayoutCollection.Add(LayoutItem);


            Center = new Point3D(-CubeR, CubeR, CubeR);
            addFace(-front, up, Background, AttachViewCube.GetBackText(this), Face.Back, Alignment.TopLeft, new Thickness(1,1,0,0));
            addFace(right, up, Background, AttachViewCube.GetRightText(this), Face.Right, Alignment.TopRight, new Thickness(0,1,1,0));
            addFace(up, right, Background, AttachViewCube.GetTopText(this), Face.Top, Alignment.TopLeft, new Thickness(1,1,0,0));
            LayoutItem = new List<Layout>();
            LayoutItem.Add(new Layout() { Face = Face.Back, Align = Alignment.TopLeft });
            LayoutItem.Add(new Layout() { Face = Face.Right, Align = Alignment.TopRight });
            LayoutItem.Add(new Layout() { Face = Face.Top, Align = Alignment.TopLeft });
            LayoutCollection.Add(LayoutItem);


            Center = new Point3D(-CubeR, -CubeR, CubeR);
            addFace(-front, up, Background, AttachViewCube.GetBackText(this), Face.Back, Alignment.TopRight, new Thickness(0,1,1,0));
            addFace(-right, up, Background, AttachViewCube.GetLeftText(this), Face.Left, Alignment.TopLeft, new Thickness(1,1,0,0));
            addFace(up, right, Background, AttachViewCube.GetTopText(this), Face.Top, Alignment.BottomLeft, new Thickness(1,0,0,1));
            LayoutItem = new List<Layout>();
            LayoutItem.Add(new Layout() { Face = Face.Back, Align = Alignment.TopRight });
            LayoutItem.Add(new Layout() { Face = Face.Left, Align = Alignment.TopLeft });
            LayoutItem.Add(new Layout() { Face = Face.Top, Align = Alignment.BottomLeft });
            LayoutCollection.Add(LayoutItem);


            Center = new Point3D(-CubeR, -CubeR, -CubeR);
            addFace(-front, up, Background, AttachViewCube.GetBackText(this), Face.Back, Alignment.BottomRight, new Thickness(0,0,1,1));
            addFace(-right, up, Background, AttachViewCube.GetLeftText(this), Face.Left, Alignment.BottomLeft, new Thickness(1,0,0,1));
            addFace(-up, -right, Background, AttachViewCube.GetBottomText(this), Face.Bottom, Alignment.TopLeft, new Thickness(1,1,0,0));
            LayoutItem = new List<Layout>();
            LayoutItem.Add(new Layout() { Face = Face.Back, Align = Alignment.BottomRight });
            LayoutItem.Add(new Layout() { Face = Face.Left, Align = Alignment.BottomLeft });
            LayoutItem.Add(new Layout() { Face = Face.Bottom, Align = Alignment.TopLeft });
            LayoutCollection.Add(LayoutItem);

            Center = new Point3D(-CubeR, CubeR, -CubeR);
            addFace(-front, up, Background, AttachViewCube.GetBackText(this), Face.Back, Alignment.BottomLeft, new Thickness(1,0,0,1));
            addFace(right, up, Background, AttachViewCube.GetRightText(this), Face.Right, Alignment.BottomRight, new Thickness(0,0,1,1));
            addFace(-up, -right, Background, AttachViewCube.GetBottomText(this), Face.Bottom, Alignment.BottomLeft, new Thickness(1,0,0,1));
            LayoutItem = new List<Layout>();
            LayoutItem.Add(new Layout() { Face = Face.Back, Align = Alignment.BottomLeft });
            LayoutItem.Add(new Layout() { Face = Face.Right, Align = Alignment.BottomRight });
            LayoutItem.Add(new Layout() { Face = Face.Bottom, Align = Alignment.BottomLeft });
            LayoutCollection.Add(LayoutItem);
            #endregion

            #region 24个侧边面

            Center = new Point3D(CubeR, -CubeR, 0);
            addFace(front, up, Background, AttachViewCube.GetFrontText(this), Face.Front, Alignment.Left, new Thickness(1,0,0,0));
            addFace(-right, up, Background, AttachViewCube.GetLeftText(this), Face.Left, Alignment.Right, new Thickness(0,0,1,0));
            LayoutItem = new List<Layout>();
            LayoutItem.Add(new Layout() { Face = Face.Front, Align = Alignment.Left });
            LayoutItem.Add(new Layout() { Face = Face.Left, Align = Alignment.Right });
            LayoutCollection.Add(LayoutItem);

            Center = new Point3D(CubeR, CubeR, 0);
            addFace(front, up, Background, AttachViewCube.GetFrontText(this), Face.Front, Alignment.Right, new Thickness(0, 0, 1, 0));
            addFace(right, up, Background, AttachViewCube.GetRightText(this), Face.Right, Alignment.Left, new Thickness(1, 0, 0, 0));
            LayoutItem = new List<Layout>();
            LayoutItem.Add(new Layout() { Face = Face.Front, Align = Alignment.Right });
            LayoutItem.Add(new Layout() { Face = Face.Right, Align = Alignment.Left });
            LayoutCollection.Add(LayoutItem);

            Center = new Point3D(-CubeR, CubeR, 0);
            addFace(-front, up, Background, AttachViewCube.GetBackText(this), Face.Back, Alignment.Left, new Thickness(1, 0, 0, 0));
            addFace(right, up, Background, AttachViewCube.GetRightText(this), Face.Right, Alignment.Right, new Thickness(0, 0, 1, 0));
            LayoutItem = new List<Layout>();
            LayoutItem.Add(new Layout() { Face = Face.Back, Align = Alignment.Left });
            LayoutItem.Add(new Layout() { Face = Face.Right, Align = Alignment.Right });
            LayoutCollection.Add(LayoutItem);

            Center = new Point3D(-CubeR, -CubeR, 0);
            addFace(-front, up, Background, AttachViewCube.GetBackText(this), Face.Back, Alignment.Right, new Thickness(0, 0, 1, 0));
            addFace(-right, up, Background, AttachViewCube.GetLeftText(this), Face.Left, Alignment.Left, new Thickness(1, 0, 0, 0));
            LayoutItem = new List<Layout>();
            LayoutItem.Add(new Layout() { Face = Face.Back, Align = Alignment.Right });
            LayoutItem.Add(new Layout() { Face = Face.Left, Align = Alignment.Left });
            LayoutCollection.Add(LayoutItem);


            Center = new Point3D(CubeR, 0, CubeR);
            addFace(front, up, Background, AttachViewCube.GetFrontText(this), Face.Front, Alignment.Top,new Thickness(0,1,0,0));
            addFace(up, right, Background, AttachViewCube.GetTopText(this), Face.Top, Alignment.Right, new Thickness(0, 0, 1, 0));
            LayoutItem = new List<Layout>();
            LayoutItem.Add(new Layout() { Face = Face.Front, Align = Alignment.Top });
            LayoutItem.Add(new Layout() { Face = Face.Top, Align = Alignment.Right });
            LayoutCollection.Add(LayoutItem);


            Center = new Point3D(CubeR, 0, -CubeR);
            addFace(front, up, Background, AttachViewCube.GetFrontText(this), Face.Front, Alignment.Bottom,new Thickness(0,0,0,1));
            addFace(-up, -right, Background, AttachViewCube.GetBottomText(this), Face.Bottom, Alignment.Right,new Thickness(0,0,1,0));
            LayoutItem = new List<Layout>();
            LayoutItem.Add(new Layout() { Face = Face.Front, Align = Alignment.Bottom });
            LayoutItem.Add(new Layout() { Face = Face.Bottom, Align = Alignment.Right });
            LayoutCollection.Add(LayoutItem);

            Center = new Point3D(-CubeR, 0, CubeR);
            addFace(-front, up, Background, AttachViewCube.GetBackText(this), Face.Back, Alignment.Top, new Thickness(0, 1, 0, 0));
            addFace(up, right, Background, AttachViewCube.GetTopText(this), Face.Top, Alignment.Left,new Thickness(1,0,0,0));
            LayoutItem = new List<Layout>();
            LayoutItem.Add(new Layout() { Face = Face.Back, Align = Alignment.Top });
            LayoutItem.Add(new Layout() { Face = Face.Top, Align = Alignment.Left });
            LayoutCollection.Add(LayoutItem);


            Center = new Point3D(-CubeR, 0, -CubeR);
            addFace(-front, up, Background, AttachViewCube.GetBackText(this), Face.Back, Alignment.Bottom, new Thickness(0, 0, 0, 1));
            addFace(-up, -right, Background, AttachViewCube.GetBottomText(this), Face.Bottom, Alignment.Left, new Thickness(1, 0, 0, 0));
            LayoutItem = new List<Layout>();
            LayoutItem.Add(new Layout() { Face = Face.Back, Align = Alignment.Bottom });
            LayoutItem.Add(new Layout() { Face = Face.Bottom, Align = Alignment.Left });
            LayoutCollection.Add(LayoutItem);

            Center = new Point3D(0, -CubeR, CubeR);
            addFace(-right, up, Background, AttachViewCube.GetLeftText(this), Face.Left, Alignment.Top, new Thickness(0, 1, 0, 0));
            addFace(up, right, Background, AttachViewCube.GetTopText(this), Face.Top, Alignment.Bottom, new Thickness(0, 0, 0, 1));
            LayoutItem = new List<Layout>();
            LayoutItem.Add(new Layout() { Face = Face.Left, Align = Alignment.Top });
            LayoutItem.Add(new Layout() { Face = Face.Top, Align = Alignment.Bottom });
            LayoutCollection.Add(LayoutItem);

            Center = new Point3D(0, CubeR, CubeR);
            addFace(right, up, Background, AttachViewCube.GetRightText(this), Face.Right, Alignment.Top, new Thickness(0, 1, 0, 0));
            addFace(up, right, Background, AttachViewCube.GetTopText(this), Face.Top, Alignment.Top, new Thickness(0, 1, 0, 0));
            LayoutItem = new List<Layout>();
            LayoutItem.Add(new Layout() { Face = Face.Right, Align = Alignment.Top });
            LayoutItem.Add(new Layout() { Face = Face.Top, Align = Alignment.Top });
            LayoutCollection.Add(LayoutItem);


            Center = new Point3D(0, -CubeR, -CubeR);
            addFace(-up, -right, Background, AttachViewCube.GetBottomText(this), Face.Bottom, Alignment.Top, new Thickness(0, 1, 0, 0));
            addFace(-right, up, Background, AttachViewCube.GetLeftText(this), Face.Left, Alignment.Bottom, new Thickness(0, 0, 0, 1));
            LayoutItem = new List<Layout>();
            LayoutItem.Add(new Layout() { Face = Face.Bottom, Align = Alignment.Top });
            LayoutItem.Add(new Layout() { Face = Face.Left, Align = Alignment.Bottom });
            LayoutCollection.Add(LayoutItem);

            Center = new Point3D(0, CubeR, -CubeR);
            addFace(-up, -right, Background, AttachViewCube.GetBottomText(this), Face.Bottom, Alignment.Bottom, new Thickness(0, 0, 0, 1));
            addFace(right, up, Background, AttachViewCube.GetRightText(this), Face.Right, Alignment.Bottom, new Thickness(0, 0, 0, 1));
            LayoutItem = new List<Layout>();
            LayoutItem.Add(new Layout() { Face = Face.Bottom, Align = Alignment.Bottom });
            LayoutItem.Add(new Layout() { Face = Face.Right, Align = Alignment.Bottom });
            LayoutCollection.Add(LayoutItem);

            #endregion

            var circle = new PieSliceVisual3D
            {
                Center = (ModelUpDirection * (-Size / 2)).ToPoint3D(),
                Normal = ModelUpDirection,
                UpVector =
                    ModelUpDirection.Equals(new Vector3D(0, 0, 1))
                        ? new Vector3D(0, 1, 0)
                        : new Vector3D(0, 0, 1),
                InnerRadius = Size,
                OuterRadius = Size * 1.3,
                StartAngle = 0,
                EndAngle = 360,
                Fill = Brushes.Red
            };
            Children.Add(circle);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="normal"></param>
        /// <param name="up"></param>
        /// <param name="b"></param>
        /// <param name="text"></param>
        private void addFace(Vector3D normal, Vector3D up, Brush b, string text, Face face,Alignment align,Thickness thickness,double size =10)
        {
            if (align == Alignment.Center)
            {
                CreateTextMaterial(b, text, thickness, true);
            }
            else
            {
                CreateTextMaterial(Background, null, thickness, false);
            }

            double a = size;

            var builder = new MeshBuilder();
            switch (face)
            {
                case Face.Top:
                    {
                        switch (align)
                        {
                            case Alignment.Top:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c1, a - c2);
                                break;
                            case Alignment.TopLeft:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c2, a - c2);
                                break;
                            case Alignment.TopRight:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c2, a - c2);
                                break;
                            case Alignment.Left:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c2, a - c1);
                                break;
                            case Alignment.Center:
                                builder.AddCubeFace(Center, normal, up, a, a - c1, a - c1);
                                break;
                            case Alignment.Right:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c2, a - c1);
                                break;
                            case Alignment.BottomLeft:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c2, a - c2);
                                break;
                            case Alignment.Bottom:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c1, a - c2);
                                break;
                            case Alignment.BottomRight:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c2, a - c2);
                                break;
                            default:
                                break;
                        }
                    }
                    break;
                case Face.Bottom:
                    {
                        switch (align)
                        {
                            case Alignment.Top:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c1, a - c2);
                                break;
                            case Alignment.TopLeft:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c2, a - c2);
                                break;
                            case Alignment.TopRight:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c2, a - c2);
                                break;
                            case Alignment.Left:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c2, a - c1);
                                break;
                            case Alignment.Center:
                                builder.AddCubeFace(Center, normal, up, a, a - c1, a - c1);
                                break;
                            case Alignment.Right:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c2, a - c1);
                                break;
                            case Alignment.BottomLeft:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c2, a - c2);
                                break;
                            case Alignment.Bottom:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c1, a - c2);
                                break;
                            case Alignment.BottomRight:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c2, a - c2);
                                break;
                            default:
                                break;
                        }
                    }
                    break;
                case Face.Left:
                    {
                        switch (align)
                        {
                            case Alignment.Top:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c1, a - c2);
                                break;
                            case Alignment.TopLeft:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c2, a - c2);
                                break;
                            case Alignment.TopRight:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c2, a - c2);
                                break;
                            case Alignment.Left:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c2, a - c1);
                                break;
                            case Alignment.Center:
                                builder.AddCubeFace(Center, normal, up, a, a - c1, a - c1);
                                break;
                            case Alignment.Right:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c2, a - c1);
                                break;
                            case Alignment.BottomLeft:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c2, a - c2);
                                break;
                            case Alignment.Bottom:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c1, a - c2);
                                break;
                            case Alignment.BottomRight:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c2, a - c2);
                                break;
                            default:
                                break;
                        }
                    }
                    break;
                case Face.Right:
                    {
                        switch (align)
                        {
                            case Alignment.Top:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c1, a - c2);
                                break;
                            case Alignment.TopLeft:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c2, a - c2);
                                break;
                            case Alignment.TopRight:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c2, a - c2);
                                break;
                            case Alignment.Left:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c2, a - c1);
                                break;
                            case Alignment.Center:
                                builder.AddCubeFace(Center, normal, up, a, a - c1, a - c1);
                                break;
                            case Alignment.Right:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c2, a - c1);
                                break;
                            case Alignment.BottomLeft:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c2, a - c2);
                                break;
                            case Alignment.Bottom:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c1, a - c2);
                                break;
                            case Alignment.BottomRight:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c2, a - c2);
                                break;
                            default:
                                break;
                        }
                    }
                    break;
                case Face.Front:
                    {
                        switch (align)
                        {
                            case Alignment.Top:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c1, a - c2);
                                break;
                            case Alignment.TopLeft:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c2, a - c2);
                                break;
                            case Alignment.TopRight:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c2, a - c2);
                                break;
                            case Alignment.Left:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c2, a - c1);
                                break;
                            case Alignment.Center:
                                builder.AddCubeFace(Center, normal, up, a, a - c1, a - c1);
                                break;
                            case Alignment.Right:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c2, a - c1);
                                break;
                            case Alignment.BottomLeft:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c2, a - c2);
                                break;
                            case Alignment.Bottom:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c1, a - c2);
                                break;
                            case Alignment.BottomRight:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c2, a - c2);
                                break;
                            default:
                                break;
                        }
                    }
                    break;
                case Face.Back:
                    {
                        switch (align)
                        {
                            case Alignment.Top:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c1, a - c2);
                                break;
                            case Alignment.TopLeft:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c2, a - c2);
                                break;
                            case Alignment.TopRight:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c2, a - c2);
                                break;
                            case Alignment.Left:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c2, a - c1);
                                break;
                            case Alignment.Center:
                                builder.AddCubeFace(Center, normal, up, a, a - c1, a - c1);
                                break;
                            case Alignment.Right:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c2, a - c1);
                                break;
                            case Alignment.BottomLeft:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c2, a - c2);
                                break;
                            case Alignment.Bottom:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c1, a - c2);
                                break;
                            case Alignment.BottomRight:
                                builder.AddCubeFace(Center, normal, up, a - c2, a - c2, a - c2);
                                break;
                            default:
                                break;
                        }
                    }
                    break;
                default:
                    break;
            }

            if (align ==Alignment.Stretch)
            {
                builder.AddCubeFace(Center, normal, up,a,a,a);
            }
            var geometry = builder.ToMesh();
            geometry.Freeze();

            var model = new GeometryModel3D { Geometry = geometry, Material = material,BackMaterial=backmaterial};
            
            var element = new ModelUIElement3D { Model = model };

            AttachViewCube.SetAlignment(element, align);
            AttachViewCube.SetFace(element, face);
            AttachViewCube.SetFlag(element, thickness);
            if (align==Alignment.Center)
            {
                switch (text)
                {
                    case "前": AttachViewCube.SetText(element, "前");  break;
                    case "后": AttachViewCube.SetText(element, "后"); break;
                    case "上": AttachViewCube.SetText(element, "上"); break;
                    case "下": AttachViewCube.SetText(element, "下"); break;
                    case "左": AttachViewCube.SetText(element, "左"); break;
                    case "右": AttachViewCube.SetText(element, "右"); break;
                    default:
                        break;
                } 
            }
            element.MouseLeftButtonUp += face_MouseLeftButtonUp;
            element.MouseMove += element_MouseMove;
            element.MouseEnter += (sender, e) =>
            {
                ModelUIElement3D ui = sender as ModelUIElement3D;
                if (AttachViewCube.GetAlignment(ui)==Alignment.Center)
                {
                    CreateTextMaterial(BackgroundMouseOver, AttachViewCube.GetText(ui), (Thickness)AttachViewCube.GetFlag(ui), true, true);
                    ((GeometryModel3D)ui.Model).Material = material;
                }
                else
                {
                    CreateTextMaterial(BackgroundMouseOver, null, (Thickness)AttachViewCube.GetFlag(ui), false, true);
                    ((GeometryModel3D)ui.Model).Material = material;
                }

                for (int i = 0; i < LayoutCollection.Count; i++)
                {
                    var item = LayoutCollection[i];
                    for (int j = 0; j < item.Count; j++)
                    {
                        if (AttachViewCube.GetAlignment(ui) == item[j].Align
                            && AttachViewCube.GetFace(ui) == item[j].Face)
                        {
                            foreach (var tem in item)
                            {
                                foreach (var modelElement in Children)
                                {
                                    if (AttachViewCube.GetFace(modelElement) == tem.Face
                                        && AttachViewCube.GetAlignment(modelElement) == tem.Align&&modelElement!=ui)
                                    {
                                        CreateTextMaterial(RelativeBackgroundMouseOver, null, (Thickness)AttachViewCube.GetFlag(modelElement), false, true);
                                        ModelUIElement3D modelui = modelElement as ModelUIElement3D;
                                        ((GeometryModel3D)(modelui.Model)).Material = material;
                                    }
                                }
                            }
                            return;
                        }
                    }
                }


            };
            element.MouseLeave += (sender, e) =>
            {
                ModelUIElement3D ui = sender as ModelUIElement3D;
                if (AttachViewCube.GetAlignment(ui) == Alignment.Center)
                {
                    CreateTextMaterial(Background, AttachViewCube.GetText(ui), (Thickness)AttachViewCube.GetFlag(element), true);
                    ((GeometryModel3D)ui.Model).Material = material;
                }
                else
                {
                    CreateTextMaterial(Background, null, (Thickness)AttachViewCube.GetFlag(element), false);
                    ((GeometryModel3D)ui.Model).Material = material;
                }
                for (int i = 0; i < LayoutCollection.Count; i++)
                {
                    var item = LayoutCollection[i];
                    for (int j = 0; j < item.Count; j++)
                    {
                        if (AttachViewCube.GetAlignment(ui) == item[j].Align
                            && AttachViewCube.GetFace(ui) == item[j].Face)
                        {
                            foreach (var tem in item)
                            {
                                foreach (var modelElement in Children)
                                {
                                    if (AttachViewCube.GetFace(modelElement) == tem.Face
                                        && AttachViewCube.GetAlignment(modelElement) == tem.Align && modelElement != ui)
                                    {
                                        CreateTextMaterial(Background, null, (Thickness)AttachViewCube.GetFlag(modelElement), false, false);
                                        ModelUIElement3D modelui = modelElement as ModelUIElement3D;
                                        ((GeometryModel3D)(modelui.Model)).Material = material;
                                    }
                                }
                            }
                            return;
                        }
                    }
                }
            };
            centerDictionary.Add(element, Center.ToVector3D());
            normalDictionary.Add(element, normal);
            upDictionary.Add(element, up);
            Children.Add(element);
        }

        private bool IsPressMove = false;
        void element_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                IsPressMove = true;
            }
        }

        /// <summary>
        /// 鼠标点击事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void face_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (!IsPressMove)
            {
                Vector3D faceNormal = normalDictionary[sender];
                Vector3D faceUp = upDictionary[sender];

                var camera = Viewport.Camera as ProjectionCamera;
                Point3D target = camera.Position + camera.LookDirection;
                double dist = camera.LookDirection.Length;
                Vector3D lookdir=new Vector3D();
                if (centerDictionary[sender].Length == 0)
                {
                    lookdir = -faceNormal;
                }
                else
                {
                    lookdir = -centerDictionary[sender];
                }
                lookdir.Normalize();
                lookdir = lookdir * dist;
                Point3D pos = target - lookdir;
                if ((faceUp.Y == 1) && AttachViewCube.GetAlignment(sender as ModelUIElement3D) != Alignment.Center)
                {
                    faceUp.Z = faceUp.Y;
                    faceUp.Y = 0;
                }
                if ((faceUp.Y == -1) && AttachViewCube.GetAlignment(sender as ModelUIElement3D) != Alignment.Center&&
                    AttachViewCube.GetFace(sender as ModelUIElement3D)==Face.Bottom)
                {
                    faceUp.Z = -faceUp.Y;
                    faceUp.Y = 0;
                }
                Vector3D updir = faceUp;
                updir.Normalize();

                CameraHelper.AnimateTo(camera, pos, lookdir, updir, 500); 
            }
        }

        private void CreateTextMaterial(Brush b, string text, Thickness thickness, bool IsCenter, bool IsMouseOver = false)
        {
            var db = new DrawingBrush
            {
                TileMode = TileMode.None,
                ViewportUnits = BrushMappingMode.Absolute,
                Viewport = new Rect(0, 0, 1, 1),
                Viewbox = new Rect(0, 0, 1, 1),
                ViewboxUnits = BrushMappingMode.Absolute
            };
            var dg = new DrawingGroup();
            DoubleCollection dc = new DoubleCollection();
            dc.Add(7);
            dc.Add(7);
            var grid = new Grid() { Width = 20, Height = 20, SnapsToDevicePixels = true, Background = b };
            if (thickness.Bottom != 0)
            {
                grid.Children.Add(new Line() { StrokeDashArray = dc, VerticalAlignment = VerticalAlignment.Bottom, X1 = 0, X2 = 20, Stroke = BorderBrush, StrokeThickness = 1 });
            }
            if (thickness.Top != 0)
            {
                grid.Children.Add(new Line() { StrokeDashArray = dc, VerticalAlignment = VerticalAlignment.Top, X1 = 0, X2 = 20, Stroke = BorderBrush, StrokeThickness = 1 });
            }
            if (thickness.Left != 0)
            {
                grid.Children.Add(new Line() { StrokeDashArray = dc, HorizontalAlignment = HorizontalAlignment.Left, Y1 = 0, Y2 = 20, Stroke = BorderBrush, StrokeThickness = 1 });
            }
            if (thickness.Right != 0)
            {
                grid.Children.Add(new Line() { StrokeDashArray = dc, HorizontalAlignment = HorizontalAlignment.Right, Y1 = 0, Y2 = 20, Stroke = BorderBrush, StrokeThickness = 1 });
            }
            grid.Arrange(new Rect(new Point(0, 0), new Size(20, 20)));
            var bmp1 = new RenderTargetBitmap((int)grid.Width, (int)grid.Height, 96, 96, PixelFormats.Default);
            bmp1.Render(grid);
            dg.Children.Add(new GeometryDrawing() { Brush = new ImageBrush() { ImageSource = bmp1 }, Geometry = new RectangleGeometry() { Rect = new Rect(0, 0, 1, 1) } });
            if (IsMouseOver)
            {
                var border = new Rectangle { Width = 20, Height = 20, SnapsToDevicePixels = true };
                border.Fill = b;
                border.StrokeThickness = 1;
                border.Stroke = BorderBrush;
                border.Arrange(new Rect(new Point(0, 0), new Size(20, 20)));
                var bmp = new RenderTargetBitmap((int)border.Width, (int)border.Height, 96, 96, PixelFormats.Default);
                bmp.Render(border);
                dg.Children.Add(new GeometryDrawing() { Brush = new ImageBrush() { ImageSource = bmp }, Geometry = new RectangleGeometry() { Rect = new Rect(0, 0, 1, 1) } });
            }
            if (IsCenter)
            {
                var ft = new FormattedText(text, CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
                                           new Typeface("Segoe UI"), 0.8, Brushes.Black);
                ft.TextAlignment = TextAlignment.Justify;
                var geometry = ft.BuildGeometry(new Point(0, 0));
                var tg = new TransformGroup();
                tg.Children.Add(new TranslateTransform(0.1, -0.10));
                if (text == "上" || text == "下")
                {
                    tg.Children[0] = new TranslateTransform(0, 0);
                    tg.Children.Add(new RotateTransform(270) { CenterX = 0.5, CenterY = 0.5 });
                }

                geometry.Transform = tg;
                dg.Children.Add(new GeometryDrawing
                {
                    Geometry = geometry,
                    Brush = Brushes.Black
                });
            }
            db.Drawing = dg;
            
            material = MaterialHelper.CreateMaterial(db);
            backmaterial = MaterialHelper.CreateMaterial(b);
        }

        #endregion
    }

    public class Layout
    {
      public  Alignment Align{get;set;}
      public Face Face { get; set; }
    }
    //public enum Alignment
    //{
    //    Top,
    //    TopLeft,
    //    TopRight,
    //    Left,
    //    Center,
    //    Right,
    //    BottomLeft,
    //    Bottom,
    //    BottomRight,
    //    Stretch
    //}
    //public enum Face
    //{
    //    Top,
    //    Bottom,
    //    Left,
    //    Right,
    //    Front,
    //    Back,
    //}
}
